Updating DLC-Live! GUI to pyside6 and multicamera support#35
Updating DLC-Live! GUI to pyside6 and multicamera support#35arturoptophys wants to merge 47 commits intoDeepLabCut:masterfrom
Conversation
…modern-python-and-pyqt6 Add Basler and GenTL camera backends for modular capture
…era-functionality
…camera-functionality Rework layout and camera handling controls
…' into artur/test_update
…r integration - Implemented `get_device_count` method in `GenTLCameraBackend` to retrieve the number of GenTL devices detected. - Added `max_devices` configuration option in `CameraSettings` to limit device probing. - Introduced `BoundingBoxSettings` for bounding box visualization, integrated into the main GUI. - Enhanced `DLCLiveProcessor` to accept a processor instance during configuration. - Updated GUI to support processor selection and auto-recording based on processor commands. - Refactored camera properties handling and removed deprecated advanced properties editor. - Improved error handling and logging for processor connections and recording states.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
… options to config
- Update configuration settings to include support for single-animal models in DLCProcessorSettings. - Improve user guide with a link to DLC documentation for model export.
…le_animal in DLCLiveProcessor settings
- Implemented MultiCameraController to manage multiple cameras simultaneously.
…fix for basler backend
…me data without tiling and track source camera ID
…ulti-camera controller
deruyter92
left a comment
There was a problem hiding this comment.
@arturoptophys, great PR! I think this is going to be super helpful.
I think we should aim to merge as soon as DeepLabCut-live 1.2 release is official. This PR is getting quite big already.
Let me know if you want me to look at specific components that you are unsure of / need help with.
Ofc it would be great to add some testing as well..
| @@ -40,8 +37,7 @@ | |||
| ), | |||
| entry_points={ | |||
| "console_scripts": [ | |||
| "dlclivegui=dlclivegui.dlclivegui:main", | |||
| "dlclivegui-video=dlclivegui.video:main", | |||
| "dlclivegui=dlclivegui.gui:main", | |||
| ] | |||
| }, | |||
| ) | |||
There was a problem hiding this comment.
I think setup.py should be removed. All information is in pyproject.toml now, and having this duplicated list of dependencies here is only confusing (or potentially conflicting). Setuptools works perfectly fine without setup.py now, since you made the pyproject.toml PEP 517 / 518 / 621–compliant.
You could keep only the following code if you want:
| from setuptools import setup | |
| # Only kept for compatibility with external legacy tools. | |
| # All information is now in pyproject.toml. | |
| setup() |
| # Install with gentl support | ||
| pip install deeplabcut-live-gui[gentl] |
There was a problem hiding this comment.
Maybe also add basler here:
| # Install with gentl support | |
| pip install deeplabcut-live-gui[gentl] | |
| # Install with gentl support | |
| pip install deeplabcut-live-gui[gentl] | |
| # Install with basler support | |
| pip install deeplabcut-live-gui[basler] |
| # Install with gentl support | ||
| pip install deeplabcut-live-gui[gentl] | ||
| ``` | ||
|
|
There was a problem hiding this comment.
Maybe add an additional block on how to install from source:
Editable Installation from Source (for contributors or advanced users)
- Clone the repository
git clone https://github.com/DeepLabCut/DeepLabCut-live-GUI.git
cd DeepLabCut-live-GUI- Install editable package using pip or the uv package manager
# Using pip
pip install -e .
# Or using uv
uv sync| 2. **Select Camera Backend**: Choose from the dropdown (opencv, gentl, aravis, basler) | ||
|
|
||
| #### Processor (optional) | ||
| 3. **Configure Camera**: Set FPS, exposure, gain, and other parameters |
There was a problem hiding this comment.
This section is not updated for the multi-camera setup yet, is it?
| The GUI supports PyTorch DLCLive models: | ||
|
|
||
| If you would not like to save the data from the session, please click `Delete Video`, and all data will be discarded. After you click `Save Video` or `Delete Video`, the `Off` button will be selected, indicating you can now set up a new session. | ||
| 1. **PyTorch**: PyTorch-based models (requires PyTorch installation) |
There was a problem hiding this comment.
Ideally the Pytorch dependency is automatically handled by DeepLabCut-live to avoid issues.
| ] | ||
|
|
||
| dependencies = [ | ||
| "deeplabcut-live", # might be missing timm and scipy |
There was a problem hiding this comment.
Let's specify this minimal version (old version is incompatible). And let's have the PyTorch dependency handled by deeplabcut-live (installs scipy, timm and torch automatically).
| "deeplabcut-live", # might be missing timm and scipy | |
| "deeplabcut-live[pytorch] >= 1.1.0" |
NOTE: the required deeplabcut-live version is not officially released yet
There was a problem hiding this comment.
on my windows machine the current dlclive3 branch installed with [pytorch] flag does not install cuda-compiled version of pytorch i had to manually install pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cu130
| LOGGER.exception("Pose inference failed", exc_info=exc) | ||
| self.error.emit(str(exc)) | ||
| finally: | ||
| self._queue.task_done() |
There was a problem hiding this comment.
I encountered this race condition: when stopping, _stop_worker() sets self._queue = None (line 236) while the worker thread is in the finally block. (I think..?)
| self._queue.task_done() | |
| if self._queue is not None: | |
| self._queue.task_done() |
| save_dict = self.get_data() | ||
| path2save = Path(__file__).parent.parent.parent / "data" / file | ||
| LOG.info(f"Path should be {path2save}") | ||
| pickle.dump(save_dict, open(path2save, "wb")) |
There was a problem hiding this comment.
Needs context manager?
| pickle.dump(save_dict, open(path2save, "wb")) | |
| with path2save.open("wb") as f: | |
| pickle.dump(save_dict, f) |
| text = value.strip() | ||
| if not text: | ||
| return {} | ||
| return json.loads(text) |
There was a problem hiding this comment.
add error handling:
| return json.loads(text) | |
| try: | |
| return json.loads(text) | |
| except json.JSONDecodeError as e: | |
| logging.warning(f"Invalid JSON in additional options: {e}. Using empty dict.") | |
| return {} |
| is_dlc_camera_frame = frame_data.source_camera_id == dlc_cam_id | ||
|
|
||
| # Update tile info and raw frame only when DLC camera frame arrives | ||
| if is_dlc_camera_frame and dlc_cam_id in frame_data.frames: |
There was a problem hiding this comment.
could fail if dlc_cam_id is None
| if is_dlc_camera_frame and dlc_cam_id in frame_data.frames: | |
| if is_dlc_camera_frame and dlc_cam_id is not None and dlc_cam_id in frame_data.frames: |
|
@deruyter92 @arturoptophys See #36 for ongoing end-to-end GUI testing efforts |
This PR supercedes the #34
Compared to the previos PR this: